"""
日历组件工具函数

包含各种实用工具函数，用于：
- 日期时间处理
- 重复规则计算
- 提醒时间计算
- 时区转换
- 数据格式化
"""

from datetime import datetime, timedelta, timezone
from typing import List, Optional, Dict, Any
import pytz
from enum import Enum


class Weekday(Enum):
    """星期枚举"""
    MONDAY = 0
    TUESDAY = 1
    WEDNESDAY = 2
    THURSDAY = 3
    FRIDAY = 4
    SATURDAY = 5
    SUNDAY = 6


class DateTimeUtils:
    """日期时间工具类"""
    
    @staticmethod
    def get_timezone(timezone_str: str) -> timezone:
        """
        获取时区对象
        
        Args:
            timezone_str: 时区字符串
            
        Returns:
            timezone: 时区对象
        """
        try:
            return pytz.timezone(timezone_str)
        except:
            return pytz.UTC
    
    @staticmethod
    def convert_timezone(dt: datetime, from_tz: str, to_tz: str) -> datetime:
        """
        转换时区
        
        Args:
            dt: 日期时间
            from_tz: 源时区
            to_tz: 目标时区
            
        Returns:
            datetime: 转换后的日期时间
        """
        from_timezone = DateTimeUtils.get_timezone(from_tz)
        to_timezone = DateTimeUtils.get_timezone(to_tz)
        
        if dt.tzinfo is None:
            dt = from_timezone.localize(dt)
        
        return dt.astimezone(to_timezone)
    
    @staticmethod
    def format_datetime(dt: datetime, format_str: str = "%Y-%m-%d %H:%M:%S") -> str:
        """
        格式化日期时间
        
        Args:
            dt: 日期时间
            format_str: 格式字符串
            
        Returns:
            str: 格式化后的字符串
        """
        return dt.strftime(format_str)
    
    @staticmethod
    def parse_datetime(dt_str: str, format_str: str = "%Y-%m-%d %H:%M:%S") -> datetime:
        """
        解析日期时间字符串
        
        Args:
            dt_str: 日期时间字符串
            format_str: 格式字符串
            
        Returns:
            datetime: 解析后的日期时间
        """
        return datetime.strptime(dt_str, format_str)
    
    @staticmethod
    def get_week_start(dt: datetime) -> datetime:
        """
        获取周的开始日期（周一）
        
        Args:
            dt: 日期时间
            
        Returns:
            datetime: 周开始日期
        """
        days_since_monday = dt.weekday()
        return dt - timedelta(days=days_since_monday)
    
    @staticmethod
    def get_month_start(dt: datetime) -> datetime:
        """
        获取月的开始日期
        
        Args:
            dt: 日期时间
            
        Returns:
            datetime: 月开始日期
        """
        return dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
    
    @staticmethod
    def get_month_end(dt: datetime) -> datetime:
        """
        获取月的结束日期
        
        Args:
            dt: 日期时间
            
        Returns:
            datetime: 月结束日期
        """
        if dt.month == 12:
            next_month = dt.replace(year=dt.year + 1, month=1, day=1)
        else:
            next_month = dt.replace(month=dt.month + 1, day=1)
        
        return next_month - timedelta(microseconds=1)
    
    @staticmethod
    def get_year_start(dt: datetime) -> datetime:
        """
        获取年的开始日期
        
        Args:
            dt: 日期时间
            
        Returns:
            datetime: 年开始日期
        """
        return dt.replace(month=1, day=1, hour=0, minute=0, second=0, microsecond=0)
    
    @staticmethod
    def get_year_end(dt: datetime) -> datetime:
        """
        获取年的结束日期
        
        Args:
            dt: 日期时间
            
        Returns:
            datetime: 年结束日期
        """
        return dt.replace(month=12, day=31, hour=23, minute=59, second=59, microsecond=999999)


class RecurrenceUtils:
    """重复规则工具类"""
    
    @staticmethod
    def get_next_occurrence(
        current_date: datetime,
        repeat_type: str,
        interval: int = 1,
        repeat_days: Optional[List[int]] = None,
        repeat_month_day: Optional[int] = None,
        repeat_month: Optional[int] = None,
        repeat_week: Optional[int] = None,
        repeat_week_day: Optional[int] = None,
        end_date: Optional[datetime] = None,
        end_count: Optional[int] = None,
        exception_dates: Optional[List[datetime]] = None
    ) -> Optional[datetime]:
        """
        获取下一个重复日期
        
        Args:
            current_date: 当前日期
            repeat_type: 重复类型
            interval: 重复间隔
            repeat_days: 重复星期几
            repeat_month_day: 重复日期
            repeat_month: 重复月份
            repeat_week: 重复第几周
            repeat_week_day: 重复星期几
            end_date: 结束日期
            end_count: 重复次数
            exception_dates: 例外日期
            
        Returns:
            Optional[datetime]: 下一个重复日期
        """
        if repeat_type == "daily":
            next_date = current_date + timedelta(days=interval)
        elif repeat_type == "weekly":
            next_date = current_date + timedelta(weeks=interval)
            if repeat_days:
                # 找到下一个指定的星期几
                while next_date.weekday() not in repeat_days:
                    next_date += timedelta(days=1)
        elif repeat_type == "monthly":
            if repeat_month_day:
                # 按日期重复
                next_month = current_date.month + interval
                next_year = current_date.year + (next_month - 1) // 12
                next_month = (next_month - 1) % 12 + 1
                
                # 处理月末日期
                last_day_of_month = (datetime(next_year, next_month + 1, 1) - timedelta(days=1)).day
                day = min(repeat_month_day, last_day_of_month)
                
                next_date = current_date.replace(year=next_year, month=next_month, day=day)
            elif repeat_week and repeat_week_day is not None:
                # 按第几个星期几重复
                next_date = RecurrenceUtils._get_nth_weekday(
                    current_date.year, current_date.month + interval, repeat_week, repeat_week_day
                )
            else:
                next_date = current_date + timedelta(days=32 * interval)  # 简化处理
        elif repeat_type == "yearly":
            if repeat_month and repeat_month_day:
                next_year = current_date.year + interval
                # 处理2月29日等特殊日期
                try:
                    next_date = current_date.replace(year=next_year, month=repeat_month, day=repeat_month_day)
                except ValueError:
                    # 如果日期不存在（如2月30日），使用该月最后一天
                    last_day = (datetime(next_year, repeat_month + 1, 1) - timedelta(days=1)).day
                    next_date = current_date.replace(year=next_year, month=repeat_month, day=last_day)
            else:
                next_date = current_date + timedelta(days=366 * interval)  # 简化处理
        else:
            return None
        
        # 检查结束条件
        if end_date and next_date > end_date:
            return None
        
        # 检查例外日期
        if exception_dates and next_date.date() in [d.date() for d in exception_dates]:
            return RecurrenceUtils.get_next_occurrence(
                next_date, repeat_type, interval, repeat_days, repeat_month_day,
                repeat_month, repeat_week, repeat_week_day, end_date, end_count, exception_dates
            )
        
        return next_date
    
    @staticmethod
    def _get_nth_weekday(year: int, month: int, week: int, weekday: int) -> datetime:
        """
        获取指定年月的第几个星期几
        
        Args:
            year: 年份
            month: 月份
            week: 第几周
            weekday: 星期几
            
        Returns:
            datetime: 日期
        """
        # 获取该月第一天
        first_day = datetime(year, month, 1)
        
        # 计算第一个目标星期几的日期
        first_target = first_day
        while first_target.weekday() != weekday:
            first_target += timedelta(days=1)
        
        # 计算第n个目标星期几的日期
        target_date = first_target + timedelta(weeks=(week - 1))
        
        # 检查是否超出该月
        if target_date.month != month:
            # 如果超出，返回该月最后一个目标星期几
            last_day = datetime(year, month + 1, 1) - timedelta(days=1)
            while last_day.weekday() != weekday:
                last_day -= timedelta(days=1)
            return last_day
        
        return target_date
    
    @staticmethod
    def generate_occurrences(
        start_date: datetime,
        end_date: datetime,
        repeat_type: str,
        interval: int = 1,
        repeat_days: Optional[List[int]] = None,
        repeat_month_day: Optional[int] = None,
        repeat_month: Optional[int] = None,
        repeat_week: Optional[int] = None,
        repeat_week_day: Optional[int] = None,
        end_count: Optional[int] = None,
        exception_dates: Optional[List[datetime]] = None
    ) -> List[datetime]:
        """
        生成重复日程的所有日期
        
        Args:
            start_date: 开始日期
            end_date: 结束日期
            repeat_type: 重复类型
            interval: 重复间隔
            repeat_days: 重复星期几
            repeat_month_day: 重复日期
            repeat_month: 重复月份
            repeat_week: 重复第几周
            repeat_week_day: 重复星期几
            end_count: 重复次数
            exception_dates: 例外日期
            
        Returns:
            List[datetime]: 重复日期列表
        """
        occurrences = []
        current_date = start_date
        
        while current_date <= end_date:
            if current_date >= start_date:
                occurrences.append(current_date)
            
            # 检查重复次数限制
            if end_count and len(occurrences) >= end_count:
                break
            
            # 获取下一个日期
            next_date = RecurrenceUtils.get_next_occurrence(
                current_date, repeat_type, interval, repeat_days, repeat_month_day,
                repeat_month, repeat_week, repeat_week_day, end_date, end_count, exception_dates
            )
            
            if not next_date or next_date > end_date:
                break
            
            current_date = next_date
        
        return occurrences


class ReminderUtils:
    """提醒工具类"""
    
    @staticmethod
    def calculate_reminder_time(
        event_time: datetime,
        minutes_before: int
    ) -> datetime:
        """
        计算提醒时间
        
        Args:
            event_time: 日程时间
            minutes_before: 提前分钟数
            
        Returns:
            datetime: 提醒时间
        """
        return event_time - timedelta(minutes=minutes_before)
    
    @staticmethod
    def should_send_reminder(
        reminder_time: datetime,
        current_time: datetime,
        is_sent: bool = False
    ) -> bool:
        """
        判断是否应该发送提醒
        
        Args:
            reminder_time: 提醒时间
            current_time: 当前时间
            is_sent: 是否已发送
            
        Returns:
            bool: 是否应该发送
        """
        if is_sent:
            return False
        
        return current_time >= reminder_time
    
    @staticmethod
    def get_reminder_message(
        event_title: str,
        event_time: datetime,
        reminder_type: str,
        minutes_before: int
    ) -> str:
        """
        生成提醒消息
        
        Args:
            event_title: 日程标题
            event_time: 日程时间
            reminder_type: 提醒类型
            minutes_before: 提前分钟数
            
        Returns:
            str: 提醒消息
        """
        time_str = DateTimeUtils.format_datetime(event_time, "%Y-%m-%d %H:%M")
        
        if minutes_before == 0:
            time_desc = "现在"
        elif minutes_before < 60:
            time_desc = f"{minutes_before}分钟后"
        elif minutes_before < 1440:
            hours = minutes_before // 60
            time_desc = f"{hours}小时后"
        else:
            days = minutes_before // 1440
            time_desc = f"{days}天后"
        
        type_map = {
            "popup": "弹窗提醒",
            "email": "邮件提醒",
            "sms": "短信提醒",
            "notification": "应用通知"
        }
        
        reminder_type_str = type_map.get(reminder_type, "提醒")
        
        return f"{reminder_type_str}：日程「{event_title}」将于{time_desc}开始（{time_str}）"


class ValidationUtils:
    """验证工具类"""
    
    @staticmethod
    def validate_color(color: str) -> bool:
        """
        验证颜色格式
        
        Args:
            color: 颜色字符串
            
        Returns:
            bool: 是否有效
        """
        if not color.startswith('#'):
            return False
        
        if len(color) not in [4, 7]:  # #RGB 或 #RRGGBB
            return False
        
        try:
            int(color[1:], 16)
            return True
        except:
            return False
    
    @staticmethod
    def validate_timezone(timezone_str: str) -> bool:
        """
        验证时区格式
        
        Args:
            timezone_str: 时区字符串
            
        Returns:
            bool: 是否有效
        """
        try:
            pytz.timezone(timezone_str)
            return True
        except:
            return False
    
    @staticmethod
    def validate_email(email: str) -> bool:
        """
        验证邮箱格式
        
        Args:
            email: 邮箱地址
            
        Returns:
            bool: 是否有效
        """
        import re
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return re.match(pattern, email) is not None
    
    @staticmethod
    def validate_time_range(start_time: datetime, end_time: datetime) -> bool:
        """
        验证时间范围
        
        Args:
            start_time: 开始时间
            end_time: 结束时间
            
        Returns:
            bool: 是否有效
        """
        return end_time > start_time
    
    @staticmethod
    def validate_recurrence_rule(
        repeat_type: str,
        interval: int,
        repeat_days: Optional[List[int]] = None,
        repeat_month_day: Optional[int] = None,
        repeat_month: Optional[int] = None,
        repeat_week: Optional[int] = None,
        repeat_week_day: Optional[int] = None
    ) -> List[str]:
        """
        验证重复规则
        
        Args:
            repeat_type: 重复类型
            interval: 重复间隔
            repeat_days: 重复星期几
            repeat_month_day: 重复日期
            repeat_month: 重复月份
            repeat_week: 重复第几周
            repeat_week_day: 重复星期几
            
        Returns:
            List[str]: 错误信息列表
        """
        errors = []
        
        if interval < 1:
            errors.append("重复间隔必须大于0")
        
        if repeat_type == "weekly" and repeat_days:
            for day in repeat_days:
                if day < 0 or day > 6:
                    errors.append("星期几必须在0-6之间")
        
        if repeat_type == "monthly":
            if repeat_month_day and (repeat_month_day < 1 or repeat_month_day > 31):
                errors.append("重复日期必须在1-31之间")
            if repeat_week and (repeat_week < 1 or repeat_week > 5):
                errors.append("重复第几周必须在1-5之间")
            if repeat_week_day is not None and (repeat_week_day < 0 or repeat_week_day > 6):
                errors.append("重复星期几必须在0-6之间")
        
        if repeat_type == "yearly":
            if repeat_month and (repeat_month < 1 or repeat_month > 12):
                errors.append("重复月份必须在1-12之间")
            if repeat_month_day and (repeat_month_day < 1 or repeat_month_day > 31):
                errors.append("重复日期必须在1-31之间")
        
        return errors


class FormatUtils:
    """格式化工具类"""
    
    @staticmethod
    def format_duration(start_time: datetime, end_time: datetime) -> str:
        """
        格式化持续时间
        
        Args:
            start_time: 开始时间
            end_time: 结束时间
            
        Returns:
            str: 格式化的持续时间
        """
        duration = end_time - start_time
        
        if duration.days > 0:
            return f"{duration.days}天"
        
        hours = duration.seconds // 3600
        minutes = (duration.seconds % 3600) // 60
        
        if hours > 0:
            return f"{hours}小时{minutes}分钟"
        else:
            return f"{minutes}分钟"
    
    @staticmethod
    def format_repeat_rule(recurrence_data: Dict[str, Any]) -> str:
        """
        格式化重复规则
        
        Args:
            recurrence_data: 重复规则数据
            
        Returns:
            str: 格式化的重复规则
        """
        repeat_type = recurrence_data.get("repeat_type", "")
        interval = recurrence_data.get("interval", 1)
        
        type_map = {
            "daily": "每天",
            "weekly": "每周",
            "monthly": "每月",
            "yearly": "每年"
        }
        
        if interval > 1:
            base_str = f"每{interval}{type_map.get(repeat_type, '')}"
        else:
            base_str = type_map.get(repeat_type, "")
        
        if repeat_type == "weekly":
            repeat_days = recurrence_data.get("repeat_days", [])
            if repeat_days:
                day_names = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
                days_str = "、".join([day_names[day] for day in repeat_days])
                base_str += f"的{days_str}"
        
        return base_str
    
    @staticmethod
    def format_priority(priority: str) -> str:
        """
        格式化优先级
        
        Args:
            priority: 优先级
            
        Returns:
            str: 格式化的优先级
        """
        priority_map = {
            "low": "低",
            "medium": "中",
            "high": "高"
        }
        return priority_map.get(priority, "中")
    
    @staticmethod
    def format_status(status: str) -> str:
        """
        格式化状态
        
        Args:
            status: 状态
            
        Returns:
            str: 格式化的状态
        """
        status_map = {
            "confirmed": "已确认",
            "tentative": "暂定",
            "cancelled": "已取消"
        }
        return status_map.get(status, "已确认")